home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
littlest
/
littl-st.lha
/
memory.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-10
|
10KB
|
451 lines
/*
Little Smalltalk, version 2
Written by Tim Budd, Oregon State University, July 1987
Improved incorporating suggestions by
Steve Crawley, Cambridge University, October 1987
Steven Pemberton, CWI, Amsterdam, Oct 1987
memory management module
This is a rather simple, straightforward, reference counting scheme.
There are no provisions for detecting cycles, nor any attempt made
at compaction. Free lists of various sizes are maintained.
At present only objects up to 255 bytes can be allocated,
which mostly only limits the size of method (in text) you can create.
reference counts are not stored as part of an object image, but
are instead recreated when the object is read back in.
This is accomplished using a mark-sweep algorithm, similar
to those used in garbage collection.
*/
# include <stdio.h>
# ifdef LIGHTC
# include <unix.h>
# include <storage.h>
# include <proto.h>
# endif
# include "env.h"
# include "memory.h"
# ifdef STRING
# include <string.h>
# endif
# ifdef STRINGS
# include <strings.h>
# endif
# ifdef ALLOC
# include <alloc.h>
# endif
# ifndef ALLOC
extern char *calloc();
# endif
boolean debugging = false;
object sysobj; /* temporary used to avoid rereference in macros */
object intobj;
object symbols; /* table of all symbols created */
/*
in theory the objectTable should only be accessible to the memory
manager. Indeed, given the right macro definitions, this can be
made so. Never the less, for efficiency sake some of the macros
can also be defined to access the object table directly
Some systems (e.g. the Macintosh) have static limits (e.g. 32K)
which prevent the object table from being declared.
In this case the object table must first be allocated via
calloc during the initialization of the memory manager.
*/
# ifdef obtalloc
struct objectStruct *objectTable;
# endif
# ifndef obtalloc
struct objectStruct objectTable[ObjectTableMax];
# endif
/*
The following variables are strictly local to the memory
manager module
FREELISTMAX defines the maximum size of any object.
*/
# define FREELISTMAX 2000
static object objectFreeList[FREELISTMAX];/* free list of objects */
# ifndef mBlockAlloc
# define MemoryBlockSize 6000
/* the current memory block being hacked up */
static object *memoryBlock; /* malloc'ed chunck of memory */
static int currentMemoryPosition; /* last used position in above */
# endif
/* initialize the memory management module */
noreturn initMemoryManager() {
int i;
# ifdef obtalloc
objectTable = obtalloc(ObjectTableMax, sizeof(struct objectStruct));
if (! objectTable)
sysError("cannot allocate","object table");
# endif
/* set all the free list pointers to zero */
for (i = 0; i < FREELISTMAX; i++)
objectFreeList[i] = nilobj;
/* set all the reference counts to zero */
for (i = 0; i < ObjectTableMax; i++) {
objectTable[i].referenceCount = 0;
objectTable[i].size = 0;
}
/* make up the initial free lists */
setFreeLists();
# ifndef mBlockAlloc
/* force an allocation on first object assignment */
currentMemoryPosition = MemoryBlockSize + 1;
# endif
/* object at location 0 is the nil object, so give it nonzero ref */
objectTable[0].referenceCount = 1;
objectTable[0].size = 0;
}
/* setFreeLists - initialise the free lists */
setFreeLists() {
int i, size;
register int z;
register struct objectStruct *p;
objectFreeList[0] = nilobj;
for (z=ObjectTableMax-1; z>0; z--) {
if (objectTable[z].referenceCount == 0){
/* Unreferenced, so do a sort of sysDecr: */
p= &objectTable[z];
size = p->size;
if (size < 0) size = ((-size) + 1)/2;
p->class = objectFreeList[size];
objectFreeList[size]= z;
for (i= size; i>0; )
p->memory[--i] = nilobj;
}
}
}
/*
mBlockAlloc - rip out a block (array) of object of the given size from
the current malloc block
*/
# ifndef mBlockAlloc
object *mBlockAlloc(memorySize)
int memorySize;
{ object *objptr;
if (currentMemoryPosition + memorySize >= MemoryBlockSize) {
/* we toss away space here. Space-Frugal users may want to
fix this by making a new object of size
MemoryBlockSize - currentMemoryPositon - 1
and putting it on the free list, but I think
the savings is potentially small */
memoryBlock = (object *) calloc((unsigned) MemoryBlockSize, sizeof(object));
if (! memoryBlock)
sysError("out of memory","malloc failed");
currentMemoryPosition = 0;
}
objptr = (object *) &memoryBlock[currentMemoryPosition];
currentMemoryPosition += memorySize;
return(objptr);
}
# endif
/* allocate a new memory object */
object allocObject(memorySize)
int memorySize;
{ int i;
register int position;
boolean done;
if (memorySize >= FREELISTMAX) {
fprintf(stderr,"size %d\n", memorySize);
sysError("allocation bigger than permitted","allocObject");
}
/* first try the free lists, this is fastest */
if ((position = objectFreeList[memorySize]) != 0) {
objectFreeList[memorySize] = objectTable[position].class;
}
/* if not there, next try making a size zero object and
making it bigger */
else if ((position = objectFreeList[0]) != 0) {
objectFreeList[0] = objectTable[position].class;
objectTable[position].size = memorySize;
objectTable[position].memory = mBlockAlloc(memorySize);
}
else { /* not found, must work a bit harder */
done = false;
/* first try making a bigger object smaller */
for (i = memorySize + 1; i < FREELISTMAX; i++)
if ((position = objectFreeList[i]) != 0) {
objectFreeList[i] = objectTable[position].class;
/* just trim it a bit */
objectTable[position].size = memorySize;
done = true;
break;
}
/* next try making a smaller object bigger */
if (! done)
for (i = 1; i < memorySize; i++)
if ((position = objectFreeList[i]) != 0) {
objectFreeList[i] =
objectTable[position].class;
objectTable[position].size = memorySize;
# ifdef mBlockAlloc
free(objectTable[position].memory);
# endif
objectTable[position].memory =
mBlockAlloc(memorySize);
done = true;
break;
}
/* if we STILL don't have it then there is nothing */
/* more we can do */
if (! done)
sysError("out of objects","alloc");
}
/* set class and type */
objectTable[position].referenceCount = 0;
objectTable[position].class = nilobj;
objectTable[position].size = memorySize;
return(position << 1);
}
object allocByte(size)
int size;
{ object newObj;
newObj = allocObject((size + 1) / 2);
/* negative size fields indicate bit objects */
sizeField(newObj) = - size;
return newObj;
}
object allocStr(str)
register char *str;
{ register object newSym;
newSym = allocByte(1 + strlen(str));
ignore strcpy(charPtr(newSym), str);
return(newSym);
}
# ifdef incr
object incrobj; /* buffer for increment macro */
# endif
# ifndef incr
void incr(z)
object z;
{
if (z && ! isInteger(z)) {
objectTable[z>>1].referenceCount++;
}
}
# endif
# ifndef decr
void decr(z)
object z;
{
if (z && ! isInteger(z)) {
if (--objectTable[z>>1].referenceCount <= 0) {
sysDecr(z);
}
}
}
# endif
/* do the real work in the decr procedure */
sysDecr(z)
object z;
{ register struct objectStruct *p;
register int i;
int size;
p = &objectTable[z>>1];
if (p->referenceCount < 0) {
fprintf(stderr,"object %d\n", z);
sysError("negative reference count","");
}
decr(p->class);
size = p->size;
if (size < 0) size = ((- size) + 1) /2;
p->class = objectFreeList[size];
objectFreeList[size] = z>>1;
if (size > 0) {
if (p->size > 0)
for (i = size; i; )
decr(p->memory[--i]);
for (i = size; i > 0; )
p->memory[--i] = nilobj;
}
p->size = size;
}
# ifndef basicAt
object basicAt(z, i)
object z;
register int i;
{
if (isInteger(z))
sysError("attempt to index","into integer");
else if ((i <= 0) || (i > sizeField(z))) {
ignore fprintf(stderr,"index %d size %d\n", i, (int) sizeField(z));
sysError("index out of range","in basicAt");
}
else
return(sysMemPtr(z)[i-1]);
return(0);
}
# endif
# ifndef simpleAtPut
void simpleAtPut(z, i, v)
object z, v;
int i;
{
if (isInteger(z))
sysError("assigning index to","integer value");
else if ((i <= 0) || (i > sizeField(z))) {
ignore fprintf(stderr,"index %d size %d\n", i, (int) sizeField(z));
sysError("index out of range","in basicAtPut");
}
else {
sysMemPtr(z)[i-1] = v;
}
}
# endif
# ifndef basicAtPut
void basicAtPut(z, i, v)
object z, v;
register int i;
{
simpleAtPut(z, i, v);
incr(v);
}
# endif
# ifdef fieldAtPut
int f_i;
# endif
# ifndef fieldAtPut
void fieldAtPut(z, i, v)
object z, v;
register int i;
{
decr(basicAt(z, i)); basicAtPut(z, i, v);
}
# endif
# ifndef byteAt
int byteAt(z, i)
object z;
register int i;
{ byte *bp;
unsigned char t;
if (isInteger(z))
sysError("indexing integer","byteAt");
else if ((i <= 0) || (i > 2 * - sizeField(z))) {
fprintf(stderr,"index %d size %d\n", i, sizeField(z));
sysError("index out of range","byteAt");
}
else {
bp = bytePtr(z);
t = bp[i-1];
fprintf(stderr,"byte at %d returning %d\n", i, (int) t);
i = (int) t;
}
return(i);
}
# endif
# ifndef byteAtPut
void byteAtPut(z, i, x)
object z;
int i, x;
{ byte *bp;
if (isInteger(z))
sysError("indexing integer","byteAtPut");
else if ((i <= 0) || (i > 2 * - sizeField(z))) {
fprintf(stderr,"index %d size %d\n", i, sizeField(z));
sysError("index out of range", "byteAtPut");
}
else {
bp = bytePtr(z);
bp[i-1] = x;
}
}
# endif
/*
Written by Steven Pemberton:
The following routine assures that objects read in are really referenced,
eliminating junk that may be in the object file but not referenced.
It is essentially a marking garbage collector algorithm using the
reference counts as the mark
*/
visit(x)
register object x;
{
int i, s;
object *p;
if (x && !isInteger(x)) {
if (++(objectTable[x>>1].referenceCount) == 1) {
/* then it's the first time we've visited it, so: */
visit(objectTable[x>>1].class);
s = sizeField(x);
if (s>0) {
p = objectTable[x>>1].memory;
for (i=s; i; --i) visit(*p++);
}
}
}
}
int objectCount()
{ register int i, j;
j = 0;
for (i = 0; i < ObjectTableMax; i++)
if (objectTable[i].referenceCount > 0)
j++;
return j;
}